﻿namespace Dyao.Book.Contract
{
    /// <summary>
    /// 任务中心参数解析基类
    /// </summary>
    public abstract class TaskCenterParametersBase : ITaskCenterParameters
    {
        /// <summary>参数字典</summary>
        internal protected IDictionary<string, object> _parametersDict;

        /// <summary>参数字典工厂</summary>
        internal protected Func<IDictionary<string, object>> _getParametersDictFactory;

        /// <summary>
        /// 任务中心参数构造
        /// </summary>
        public TaskCenterParametersBase()
        {
        }

        /// <summary>
        /// 任务中心参数构造
        /// </summary>
        /// <param name="sourceParameters"></param>
        /// <param name="parameters">参数</param>
        /// <param name="options">系列化选项</param>
        public TaskCenterParametersBase(IDictionary<string, object> parameters)
        {
            this._parametersDict = parameters ?? throw new ArgumentNullException(nameof(parameters));
        }

        /// <summary>
        /// 任务中心参数构造
        /// </summary>
        /// <param name="dictFatory"></param>
        public TaskCenterParametersBase(Func<IDictionary<string, object>> dictFatory)
        {
            _getParametersDictFactory = dictFatory ?? throw new ArgumentNullException(nameof(dictFatory));
        }

        /// <summary>
        /// 参数
        /// </summary>
        public virtual IDictionary<string, object> Parameters => _parametersDict ??= _getParametersDictFactory?.Invoke();

        /// <summary>
        /// 是否有参数
        /// </summary>
        public virtual bool HasParameters => Parameters != null && Parameters.Count > 0;

        /// <summary>
        /// 是否存在key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual bool IsExists(string key)
        {
            return HasParameters && Parameters.ContainsKey(key);
        }

        /// <summary>
        /// 获取所有key
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<string> GetKeys()
        {
            if (HasParameters)
            {
                foreach (var key in Parameters.Keys)
                {
                    yield return key;
                }
            }
        }

        /// <summary>
        /// 尝试获取值，返回是否获取成功
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual bool TryGetValue(string key, out object value)
        {
            value = default;

            return HasParameters && Parameters.TryGetValue(key, out value);
        }

        /// <summary>
        /// 尝试获取值，返回是否获取成功
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public virtual bool TryGetValue<T>(string key, out T value)
        {
            value = default;

            return HasParameters
                && Parameters.TryGetValue(key, out var obj)
                && TryDeserialize(obj, out value);
        }

        /// <summary>
        /// 尝试将参数字符串反序列化为 <typeparamref name="T"/> <paramref name="model"/>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual bool TryDeserializeParametersTo<T>(out T model)
        {
            model = default;

            if (_parametersDict != null && _parametersDict is T t)
            {
                model = t;
                return true;
            }

            var str = GetParametersString();
            return str != null && TryDeserialize(str, out model);

        }

        /// <summary>
        /// 反序列化
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="value">参数值</param>
        /// <returns>返回 <paramref name="type"/> 类型的对象实例 </returns>
        public abstract object Deserialize(Type type, object value);

        /// <summary>
        /// 转为字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString() => GetParametersString();

        /// <summary>
        /// 尝试反序列化
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual bool TryDeserialize<T>(object value, out T model)
        {
            model = default;

            if (value is T m)
            {
                model = m;

                return true;
            }

            if (value != null)
            {
                try
                {
                    model = (T)Deserialize(typeof(T), value);
                    return true;
                }
                catch (Exception)
                {
                }
            }

            return false;
        }

        /// <summary>
        /// 获取参数原始字符串
        /// </summary>
        /// <returns></returns>
        protected abstract string GetParametersString();
    }
}
